package main

import (
	"context"
	"fmt"
	"time"

	ble "github.com/go-ble/ble"
	"github.com/go-ble/ble/linux"
)

var (
	serviceUUID = ble.MustParse("0000ffff-0000-1000-8000-00805f9b34fb")
	writeUUID   = ble.MustParse("0000ff01-0000-1000-8000-00805f9b34fb")
	notifyUUID  = ble.MustParse("0000ff02-0000-1000-8000-00805f9b34fb")
)

func main() {
	dev, err := linux.NewDevice()
	if err != nil {
		panic(err)
	}
	ble.SetDefaultDevice(dev)

	svc := ble.NewService(serviceUUID)

	wr := ble.NewCharacteristic(writeUUID)
	wr.Prop.Write = true
	wr.Prop.WriteNR = true

	nf := ble.NewCharacteristic(notifyUUID)
	nf.Prop.Notify = true
	nf.Prop.Read = true

	notifyValue := []byte("ready")
	nf.HandleRead(func(req ble.Request, rsp ble.ResponseWriter) {
		rsp.Write(notifyValue)
	})

	notifyChan := make(chan []byte, 16)
	nf.HandleNotify(func(req ble.Request, n ble.Notifier) {
		go func() {
			for {
				data := <-notifyChan
				if len(data) > 0 {
					_, _ = n.Write(data)
				}
			}
		}()
	})

	wr.HandleWrite(func(req ble.Request, rsp ble.ResponseWriter) {
		b := req.Data()
		if len(b) == 0 {
			rsp.Write([]byte{})
			return
		}
		notifyValue = append([]byte{}, b...)
		select {
		case notifyChan <- notifyValue:
		default:
		}
		rsp.Write([]byte{})
	})

	svc.AddCharacteristic(wr)
	svc.AddCharacteristic(nf)
	ble.AddService(svc)

	ctx := context.Background()
	go func() {
		for {
			_ = ble.AdvertiseNameAndServices(ctx, "Go-GATT", serviceUUID)
			time.Sleep(2 * time.Second)
		}
	}()

	fmt.Println("Advertising as Go-GATT with service FFFF, ready to accept connections")
	select {}
}